/** @file    URI.cpp
 *  @author  Alessandro Polo
 *  @version $Id: URI.cpp 2829 2010-08-02 20:45:47Z alex $
 *  @brief
 * File containing methods for the wosh::URI class.
 * The header for this class can be found in URI.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/URI.h>
 #include <core/ObjectAllocator.h>
 #include <core/WoshKernel.h>
 #include <core/Functional.h>
 #include <core/Tree.h> // collector
//#include <QRegExp>


using namespace std;
namespace wosh {

 WOSH_REGISTER(wosh::URI, "wosh::ISerializable", 1.01, _static_URI)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
 
URI::URI()
	: global(false) { }
 
URI::URI( const std::string& uristr )
	: global(false) {
	fromString(uristr);
 }

URI::URI( const URI& m )
	: kernel_name(m.kernel_name), name(m.name), path(m.path), expr(m.expr), global(false) { }

URI::URI( const URI& parent, const std::string& name )
	: kernel_name(parent.kernel_name), name(name), path(parent.path), global(false) { 
	path.push_back(parent.name);
 }

URI::~URI() {
	if ( this->global )
		unRegisterGlobal();
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT URI::registerGlobal() {
	if ( isEmpty() ) return WRET_ERR_ILLEGAL_USE;
	this->global = true;
	URICollector::getInstance().registerGlobal( this );
	return WRET_OK;
 }

WRESULT URI::unRegisterGlobal() {
	URICollector::getInstance().unRegisterGlobal( this );
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void URI::setPath( const std::string& value ) {
	this->path.clear();
	Utilities::splitString(value, _URI_PATH_Separator, this->path, false);
 }

void URI::setKernelLocal() {
	this->kernel_name = WoshKernel::getKernelName();
 }

void URI::setParent( const URI& value ) {
	this->kernel_name = value.kernel_name;
	this->path = value.path;
	if ( !value.name.empty() )
		this->path.push_back(value.name);
 }

void URI::setAny() {
	this->kernel_name = _URI_WILDCHAR;
	this->path.clear();
	this->path.push_back(_URI_WILDWILDCHAR);
	this->name = _URI_WILDCHAR;
 }

void URI::setAnyButName( const std::string& value ) {
	this->kernel_name = _URI_WILDCHAR;
	this->path.clear();
	this->path.push_back(_URI_WILDWILDCHAR);
	this->name = value;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT URI::replaceField( const std::string& key, const ISerializable* value ) {
	if ( key.empty() ) {
		if ( value == NULL )
			clear();
		else if ( value->isKindOf<Variant>() && value->as<Variant>()->isString() )
			fromString( value->as<Variant>()->asString() );
		else if ( value->isKindOf<URI>() )
			*this = *(value->as<URI>());
		return WRET_OK;
	 }
	string valueStr = "";
	if ( value != NULL && value->isKindOf<Variant>() && value->as<Variant>()->isString() )
		valueStr = value->as<Variant>()->asString();
	else return WRET_ERR_PARAM;
	if ( key == "Kernel" )
		this->kernel_name = value->as<Variant>()->asString();
	else if ( key == "Path" )
		setPath( value->as<Variant>()->asString() );
	else if ( key == "Name" )
		this->name = value->as<Variant>()->asString();
	else if ( key == "Expression" )
		this->expr.fromString( value->as<Variant>()->asString() );
	else
		return WRET_ERR_ILLEGAL_USE;
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void URI::clear() {
	this->kernel_name = "";
	this->path.clear();
	this->name = "";
	this->expr.clear();
 }

void URI::clearPathName() {
	this->path.clear();
	this->name = "";
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool URI::isChildOf( const URI& parent, bool strict ) const
 {
	if ( !pregMatchKernel( parent, *this ) )
		return false;

	if ( this->path.size() == 0 && !parent.getName().empty() )
		return false;

	if ( parent.path.size() == 0 ) {
		if ( this->path.at(0) == _URI_WILDWILDCHAR || this->path.at(0) == parent.getName() ) {
			if ( strict && this->path.size() != 1 )
				return false;
			return true;
		 }
		else
			return false;
	}

	// any path node: validates when strict!
	if ( this->path.size() == 1 && this->path.at(0) == _URI_WILDWILDCHAR ) {
		if ( !strict )
			return true;
	}

	if ( strict ) {
		// so last node of the path MUST be the parent's name!
		if ( this->path.back() != parent.getName() )
			return false;
		// maybe there is a ** pattern?
	 }

	std::vector<std::string>::const_iterator it_par = parent.path.begin();
	std::vector<std::string>::const_iterator it_par_last = parent.path.end();
	std::vector<std::string>::const_iterator it_child;
	std::vector<std::string>::const_iterator it_child_last = this->path.end(); it_child_last--;//parent is @ size-2

	for ( it_child=this->path.begin(); it_child!=it_child_last; ++it_child, ++it_par ) {
		if ( it_par == it_par_last )
			return !strict; // walked my path, it's ok but there are more child-parents
		if ( *it_child == _URI_WILDCHAR )
			continue;
		if ( *it_par != *it_child )
			return false;
	 }
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

URI URI::getParent() const {
	URI temp;
	temp.kernel_name = this->kernel_name;
	if ( this->path.empty() )
		return temp;
	if ( this->path.size() == 1 ) {
		temp.name = this->path.at(0);
		return temp;
	 }
	temp.path = this->path;
	temp.path.pop_back();
	temp.name = this->path.back();
	return temp;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool URI::isEmpty() const {
	if ( !this->kernel_name.empty() ) return false;
	if ( !this->path.empty() ) return false;
	if ( !this->name.empty() ) return false;
	return true;
 }

bool URI::isKernelLocal() const {
	if ( this->kernel_name == "" ) return true;
	if ( this->kernel_name == WoshKernel::getKernelName() ) return true;
	return false;
 }

bool URI::isValid() const {
	if ( this->kernel_name == "" )
		return false;
	if ( this->kernel_name.find(_URI_KERNEL_Separator) != std::string::npos )
		return false;
	if ( this->name.find(_URI_PATH_Separator) != std::string::npos )
		return false;
	// cos of expressions
	if ( this->name.find("[") != std::string::npos ) return false;
	if ( this->name.find("]") != std::string::npos ) return false;
	if ( !this->path.empty() ) {
		std::vector<std::string>::const_iterator it;
		for ( it=this->path.begin(); it!=this->path.end(); ++it ) {
			if ( (*it).find(_URI_PATH_Separator) != std::string::npos )
				return false;
		 }
	 }
	if ( !this->expr.isValid() ) return false;
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool URI::exists() const {
	return URICollector::getInstance().exists(this);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

URI& URI::operator=(const URI& m){
	if (this == &m) return *this; // same object?
	this->kernel_name = m.kernel_name;
	this->name = m.name;
	this->expr = m.expr;
	this->path.resize( m.path.size() );
	std::copy( m.path.begin(), m.path.end(), this->path.begin() );
	return *this;
}

bool URI::operator==(const URI& other) const {
	if ( this->kernel_name != other.kernel_name ) return false;
	if ( this->name != other.name ) return false;
	if ( this->path.size() != other.path.size() ) return false;
	if ( this->expr != other.expr ) return false;
	std::vector<std::string>::const_iterator it;
	std::vector<std::string>::const_iterator it_mine = this->path.begin();
	for ( it=other.path.begin(); it!=other.path.end(); ++it, ++it_mine) {
		if ( *it != *it_mine ) return false;
	 }
	return true;
 }

bool URI::operator>(const URI& other) const {
	if ( this->kernel_name > other.kernel_name ) return true;
	else if ( this->kernel_name < other.kernel_name ) return false;
	if ( this->path.size() > other.path.size() ) return true;
	if ( this->path.size() < other.path.size() ) return false;
	std::vector<std::string>::const_iterator it;
	std::vector<std::string>::const_iterator it_mine = this->path.begin();
	for ( it=other.path.begin(); it_mine!=this->path.end(); ++it, ++it_mine ) {
		if ( it == other.path.end() ) return false;
		if ( *it > *it_mine ) return true;
		if ( *it < *it_mine ) return false;
	 }
	if ( this->name > other.name ) return true;
	else if ( this->name < other.name ) return false;
	return true;
 }

bool URI::operator<(const URI& other) const {
	if ( this->kernel_name < other.kernel_name ) return true;
	else if ( this->kernel_name > other.kernel_name ) return false;
	if ( this->path.size() < other.path.size() ) return true;
	if ( this->path.size() > other.path.size() ) return false;
	std::vector<std::string>::const_iterator it;
	std::vector<std::string>::const_iterator it_mine = this->path.begin();
	for ( it=other.path.begin(); it!=other.path.end(); ++it, ++it_mine ) {
		if ( *it < *it_mine ) return true;
		if ( *it > *it_mine ) return false;
	 }
	if ( this->name < other.name ) return true;
	else if ( this->name > other.name ) return false;
	return false;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool URI::pregMatchStep( const std::string& regex, const std::string& item )
 {
	if ( regex == _URI_WILDCHAR ) // pattern is WILDCHAR, fine!
		return true;
	if ( regex == item ) // same std::string, fine!
		return true;
	if ( regex.size() == 0 )
		return false;

	// '~' prefix means similar-comparison
	if ( regex.at(0) == '~' && Utilities::compare_string_X(item, regex.substr(1)) > 80 )
		return true;

	if ( Utilities::evalRegexWildChar(regex.c_str(), item.c_str()) == 0 )
		return true;

return false;
	//QRegExp rx( regexURI.getKernelName().c_str() );
	//rx.setPatternSyntax(QRegExp::Wildcard);
	//return rx.exactMatch( item.getKernelName().c_str() );
 }

bool URI::pregMatchKernel( const URI& regexURI, const URI& item ) {
	return pregMatchStep( regexURI.getKernelName(), item.getKernelName() );
 }

bool URI::pregMatch( const URI& regexURI, const URI& itemURI ) {
	// wosh123:/**/*
	// wosh123:/**/asd
	// wosh123:/*/asd
	// wosh123:/asd/*
	// wosh123:/asd/fgh
	//no? wosh123:/asd/**
	//no? wosh123:/*/asd/**
	//no? wosh123:/asd/*/**
	// *:/asd/bfg*
	// *:/asd/*bfg
	// *:/**/bfg*

	if ( !pregMatchKernel(regexURI, itemURI) )
		return false;
	// => kernels match

	if ( !pregMatchStep(regexURI.getName(), itemURI.getName()) )
		return false;
	// => names match or patter is WILDCHAR (*)

	if ( regexURI.isPathEmpty() ) { // its a root element
		if ( itemURI.isPathEmpty() ) // great! they match!
			return true;
	 }
	if ( regexURI.isPathAny() ) { // great! any PATH is valid!
		return true;
	 }
	// => we must walk the paths and compare them

	if ( itemURI.isPathEmpty() ) { // regext path is not empty and won't validate
		return false;
	 }
	// => so we should just check the paths!

	std::vector<std::string>::const_iterator it_uri = itemURI.path.begin();

	string token;
	//short wildwild = 0;
	std::vector<std::string>::const_iterator it_rgx;
	for ( it_rgx=regexURI.path.begin(); it_rgx!=regexURI.path.end(); ++it_rgx ) {
		token = *it_rgx;

		if ( it_uri == itemURI.path.end() ) // is path finished already!?
			return false;

		if ( token == _URI_WILDCHAR ) {
			// current path-step is verifyed
		 }
		else if ( token.at(0) == '~' ) {
			if ( Utilities::compare_string_X(*it_uri, token.substr(1)) < 80 ) // current path-step doesn't match
				return false;
		 }
		else if ( token != *it_uri )
			return false;

		++it_uri;
	 }
	// we walked both path till end, great!
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool URI::extractExpression( const std::string& input, std::string& name, UriExpression& expression ) {
	size_t pos = input.find("[");
	 if ( pos == std::string::npos ) {
		name = input;
		return false;
	  }
	 name = input.substr(0, pos);
	 expression.fromString( input.substr(pos) );
	 return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void URI::fromString( const std::string& value ) {
	clear();
	if ( value.size() == 0 ) return;
	string temp = "";
	std::size_t found = value.find(_URI_KERNEL_Separator);
	if ( found == 0 ) {
		// empty kernel means LOCAL kernel
		this->kernel_name = WoshKernel::getKernelName();
		temp = value.substr(1);
	 }
	else if ( found == std::string::npos ) {
		// kernel separator (:) not found
		if ( value.find(_URI_PATH_Separator) == std::string::npos ) {
			// no separators, target is kernel?
			this->kernel_name = value;
			URI::extractExpression( value, this->kernel_name, this->expr );
			return;
		 }
		// something like Media/zone1, assume local kernel!
		this->kernel_name = WoshKernel::getKernelName();
		// target is kernel?
		temp = value;
	 }
	else {
		// pop the kernel name
		this->kernel_name = value.substr(0, found);
		temp = value.substr(found+1);
	 }
	// path contains PATH/NAME[expression]
	Utilities::splitString(temp, _URI_PATH_Separator, this->path, false, true);
	if ( this->path.size() == 0 )
		return;
	temp = this->path.back();
	this->path.pop_back();
	URI::extractExpression( temp, this->name, this->expr );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

std::string URI::toString() const {
	if ( isEmpty() ) return "";
	if ( isPathEmpty() ) {
		if ( this->name.empty() )
			return this->kernel_name;
		else
			return this->kernel_name + _URI_KERNEL_Separator + this->name + this->expr.toString();
	 }
	return this->kernel_name + _URI_KERNEL_Separator + Utilities::joinVector(this->path, _URI_PATH_Separator) + _URI_PATH_Separator + this->name + this->expr.toString();
 }

bool URI::updateHash( DataHashContext* hash_context ) const {
	if ( hash_context == NULL ) return false;
	bool ret = true;
	ret = hash_context->update( toString() );
	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

URI URI::LocalKernel() {
	return URI( WoshKernel::getKernelName() );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UriExpression::clear() {
	this->predicates.clear();
 }

void UriExpression::setPredicate( const std::string& field, const std::string& value, char comparison ) {
	std::vector<UriPredicate>::iterator it;
	for ( it=this->predicates.begin(); it!=this->predicates.end(); ++it ) {
		if ( (*it).field != field ) continue;
		(*it).value != value;
		return;
	 }
	UriPredicate p;
	p.field = field;
	p.value = value;
	p.comparison = comparison;
	p.or_and = true;
	this->predicates.push_back(p);
 }

UriExpression& UriExpression::operator=(const UriExpression& m){
	if (this == &m) return *this; // Same object?
	this->clear();
	std::vector<UriPredicate>::const_iterator it;
	for ( it=m.predicates.begin(); it!=m.predicates.end(); ++it ) {
		setPredicate( (*it).field, (*it).value, (*it).comparison );
	 }
	return *this;
}

bool UriExpression::operator==(const UriExpression& other) const {
	if ( this->predicates.size() != other.predicates.size() )
		return false;
	std::vector<UriPredicate>::const_iterator it;
	std::vector<UriPredicate>::const_iterator it_mine = this->predicates.begin();
	for ( it=other.predicates.begin(); it!=other.predicates.end(); ++it, ++it_mine ) {
		if ( (*it).field != (*it_mine).field )
			return false;
		if ( (*it).value != (*it_mine).value )
			return false;
		if ( (*it).comparison != (*it_mine).comparison )
			return false;
	 }
	return true;
 }

UriPredicate UriExpression::getPredicate( int index ) const {
	if ( index < 0 ||  index >= (int)this->predicates.size() )
		return UriPredicate();
	return this->predicates.at(index);
 }

UriPredicate UriExpression::getPredicate( const std::string& field ) const {
	std::vector<UriPredicate>::const_iterator it;
	for ( it=this->predicates.begin(); it!=this->predicates.end(); ++it ) {
		if ( (*it).field != field ) continue;
		return *it;
	 }
	return UriPredicate();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UriExpression::fromString( const std::string& input ) {
	string tmp = input;
	Utilities::trimSpaces(tmp);
	if ( tmp.size() < 2 ) return;
	if ( tmp.at(0) == '[' ) tmp.erase(0,1);
	if ( tmp.at(tmp.size()-1) == ']' ) tmp.erase(tmp.size()-1);
	std::vector<string> items;
	UriPredicate pred;
	Utilities::splitString(tmp, ";", items, false, false);
	std::vector<string>::const_iterator it;
	for ( it=items.begin(); it!=items.end(); ++it ) {
		if ( (*it).find('=') != std::string::npos )
			pred.comparison = '=';
		else if ( (*it).find('~') != std::string::npos )
			pred.comparison = '~';
		else {
			continue;
		 }
		size_t pos = (*it).find(pred.comparison);
		if ( (*it).at(0) == '&' ) {
			pred.field = (*it).substr(1, pos);
			pred.or_and = true;
		 }
		else if ( (*it).at(0) == '|' ) {
			pred.field = (*it).substr(1, pos);
			pred.or_and = false;
		 }
		else {
			pred.field = (*it).substr(0, pos);
			pred.or_and = true;
		 }
		pred.value = (*it).substr(pos+1);
		setPredicate( pred.field, pred.value, pred.comparison );
	 }
 }

string UriExpression::toString() const {
	if ( this->predicates.empty() )
		return "";
	string temp = "[";
	std::vector<UriPredicate>::const_iterator it;
	for ( it=this->predicates.begin(); it!=this->predicates.end(); ++it ) {
		temp += (*it).field + (*it).comparison + (*it).value;
		if ( it == predicates.end()-1 ) continue;
		temp += ";";
		if ( (*it).or_and )
			temp += ";&";
		else
			temp += ";|";

	 }
	temp += "]";
	return temp;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

// expensive, BUGGY
long listChildren( NodeUriStr* cNode, const URI* parent_uri, std::vector<ISerializable*>& output_list, int recursive ) {
	if ( cNode == NULL ) return 0;
	long count = 0;
	URI* cUri = NULL;
	if ( cNode->getParent() == NULL ) { // children are kernels must be a kernel
		;
	 }
	else if ( parent_uri == NULL ) {
		cUri = new URI( cNode->getContent() );
		output_list.push_back( cUri );
		++count;
	 }
	else {
		cUri = new URI(*parent_uri, cNode->getContent());
		output_list.push_back( cUri );
		++count;
	 }
	if ( recursive <= 0 )
		return count;

	cNode->getChildren().transactionBeginRead();
	NodeUriStr::tTreeNodeTList::Iterator it;
	const NodeUriStr::tTreeNodeTList::ConstIterator it_end = cNode->getChildren().end();
	for ( it=cNode->getChildren().begin(); it!= it_end; ++it ) {
		count += listChildren( *it, cUri, output_list, recursive-1 );
	 }
	cNode->getChildren().transactionEnd();
	return count;
 }

long listURI( NodeUriStr* parent_node, const URI& compare_uri, const URI* parent_uri, bool recursive, short compare_mode, std::vector<ISerializable*>* output_list, int path_index = -1 )
 {
	if ( parent_node == NULL ) return -1;
	long count = 0;
	const std::string* cName = NULL; // current part of the URI to be compared

	if ( path_index < 0 )
		cName = &compare_uri.getKernelName();
	else if ( path_index < (int)compare_uri.getPath().size() )
		cName = &compare_uri.getPath().at(path_index);
	else if ( path_index == (int)compare_uri.getPath().size() )
		cName = &compare_uri.getName();
	else {
		// walked through the end!
		if ( parent_uri != NULL )
			return listChildren( parent_node, &parent_uri->getParent(), *output_list, (int)recursive );
		return count;
	 }
	URI currUri;
	if ( parent_uri != NULL )
		currUri.setParent(*parent_uri);

	parent_node->getChildren().transactionBeginRead();
	NodeUriStr::tTreeNodeTList::Iterator it;
	const NodeUriStr::tTreeNodeTList::ConstIterator it_end = parent_node->getChildren().end();
	for ( it=parent_node->getChildren().begin(); it!= it_end; ++it ) {
		bool found = false;
		if ( cName == NULL )
			found = true;
		else if ( compare_mode == 1 )
			found = ( (*it)->getContent() == *cName );
		else
			found = URI::pregMatchStep( *cName, (*it)->getContent() );
		if ( !found ) continue;
		if ( parent_uri == NULL )
			currUri.setKernelName( (*it)->getContent() );
		else
			currUri.setName( (*it)->getContent() );
		count += listURI( *it, compare_uri, &currUri, recursive, compare_mode, output_list, path_index+1 );
	 }

	parent_node->getChildren().transactionEnd();
	return count;
 }

// return most similar depth BUGGY
int searchNodes( const URI& uri, int path_index, NodeUriStr* cNode, short compare_mode )
 {
	if ( cNode == NULL ) return -1;
	const std::string* cName = NULL; // current part of the URI to be compared
	if ( path_index < 0 )
		cName = &uri.getKernelName();
	else if ( path_index < (int)uri.getPath().size() )
		cName = &uri.getPath().at(path_index);
	else if ( path_index == (int)uri.getPath().size() )
		cName = &uri.getName();
	else
		return path_index;

	cNode->getChildren().transactionBeginRead();
	NodeUriStr::tTreeNodeTList::Iterator it;
	const NodeUriStr::tTreeNodeTList::ConstIterator it_end = cNode->getChildren().end();
	for ( it=cNode->getChildren().begin(); it!= it_end; ++it ) {
		bool found = false;
		if ( compare_mode == 1 ) {
			found = ( (*it)->getContent() == *cName );
		 }
		else {
			found = URI::pregMatchStep( *cName, (*it)->getContent() );
		 }
		if ( !found ) continue;
		int retv = searchNodes( uri, path_index+1, *it, compare_mode );
		cNode->getChildren().transactionEnd();
		return retv;
	 }

	cNode->getChildren().transactionEnd();
	return path_index-1;
 }

int editNode( const URI& uri, int path_index, NodeUriStr* cNode, short action ) {
	if ( cNode == NULL ) return -1;
	const std::string* cName = NULL;
	if ( path_index < 0 )
		cName = &uri.getKernelName();
	else if ( path_index < (int)uri.getPath().size() )
		cName = &uri.getPath().at(path_index);
	else if ( path_index == (int)uri.getPath().size() )
		cName = &uri.getName();
	else
		return path_index;

	// validate 'cName' regex.. should be AVOIDED

	cNode->getChildren().transactionBeginWrite();
	NodeUriStr::tTreeNodeTList::Iterator it = std::find_if(cNode->getChildren().begin(), cNode->getChildren().end(),
		Functor_Validator<TreeNodeT<std::string>, const std::string&>(*cName, &TreeNodeT<std::string>::getContent ) );
	NodeUriStr* childNode = NULL;

	if ( action == -1 ) { // destroy
		if ( it == cNode->getChildren().end() ) {
			cNode->getChildren().transactionEnd();
			return path_index;
		 } // else forward
		childNode = *it;
	 }
	else if ( action == 1 ) { // create
		if ( it == cNode->getChildren().end() )
			childNode = cNode->addChild( *cName );
		else // forward
			childNode = *it;
	 }
	int retv = editNode( uri, path_index+1, childNode, action );
	cNode->getChildren().transactionEnd();
	return retv;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

// meyer singleton, created on first use, destroyed by compiler
// the tree is free on destructor
URICollector& URICollector::getInstance() {
	static URICollector static_uri_collector;
	return static_uri_collector;
 }

URICollector::URICollector() {
	NodeUriStr* rootNode = new NodeUriStr( "root", NULL );
	this->URIs.setRoot(rootNode);
 }

URICollector::~URICollector() {
	this->URIs.free(true, true);// called by dynamic-deinit (of compiler) so it's single-thread mode
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void URICollector::registerGlobal( const URI* uri ) {
	if ( uri == NULL ) return;
	int depth = editNode( *uri, -1, this->URIs.getRoot(), 1 );
	(void)depth;
 }

void URICollector::unRegisterGlobal( const URI* uri ) {
	if ( uri == NULL ) return;
	int depth = editNode( *uri, -1, this->URIs.getRoot(), -1 );
	(void)depth;
 }

bool URICollector::exists( const URI* uri, short compare_mode ) {
	if ( uri == NULL ) return false;
	int depth = searchNodes( *uri, -1, this->URIs.getRoot(), compare_mode );
	return ( depth == (int)uri->getPath().size()+1 );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

URI URICollector::resolve( NodeUriStr* node ) {
	if ( node == NULL ) return URI();
	if ( node->getParent() == getInstance().URIs.getRoot() ) { // it's a kernel URI node (such as 'wosh1')
		return URI( node->getContent() );
	 }
	URI temp;
	temp.setName( node->getContent() );
	NodeUriStr* currentNode = node->getParent();
	while ( currentNode != NULL ) {
		if ( currentNode->getParent() == getInstance().URIs.getRoot() ) {
			temp.setKernelName(currentNode->getContent());
			break;
		 }
		temp.getPath().insert( temp.getPath().begin(), currentNode->getContent() );
		currentNode = currentNode->getParent();
	 }
	return temp;
 }

long URICollector::list( const URI* parent, bool recursive, std::vector<ISerializable*>& all_uris ) {
	return listURI( this->URIs.getRoot(), *parent, NULL, recursive, 0, &all_uris );
	//listNodes( rootNode, parent, recursive, all_uris );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

}; // namespace wosh
